home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 3 / Info_Mac_1994-01.iso / Development / Source / MultiSession 1.04 Source / Core 27⁄June⁄1993 / EventLoop.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-05  |  15.9 KB  |  593 lines  |  [TEXT/KAHL]

  1. /* EventLoop.c */
  2.  
  3. #define COMPILING_EVENTLOOP_C
  4. #include "EventLoop.h"
  5. #include "CMyApplication.h"
  6. #include "CMyScrap.h"
  7. #include "MenuController.h"
  8. #include "CWindow.h"
  9. #include "CViewRect.h"
  10. #include "CSack.h"
  11. #include "Compatibility.h"
  12. #include "Memory.h"
  13.  
  14.  
  15. #define RELINQUISHSLEEPTIME (1)
  16. #define JudiciousDelay (5)
  17.  
  18. ulong                SleepTime = DefaultSleepTime;
  19. CSack*            ListOfIdlers;
  20. CSack*            ListOfIdlerWannabees;
  21. Rect                BoundsRect;
  22. ulong                LastEventTime = 0;
  23. MyBoolean        QuitPending = False;
  24. ulong                LastCursorTime;
  25. CSack*            DeadIdlersList;
  26. ulong                LastIdleTime = 0;
  27. MyBoolean        WeAreActiveApplication = True;
  28. MyBoolean        ModalWindowTerminationFlag = False;
  29. ulong                LastJudiciousRelease = 0;
  30.  
  31. CViewRect*    LastMouseDownViewRect;
  32. CViewRect*    KeyReceiverViewRect;
  33. CViewRect*    LastKeyDownViewRect;
  34.  
  35. short                LastModifiers = 0;
  36. ulong                LastModifiersTime = 0;
  37.  
  38.  
  39. /* initialize data structures */
  40. void        InitMyEventLoop(void)
  41.     {
  42.         BoundsRect = screenBits.bounds;
  43.         InsetRect(&BoundsRect,4,4);
  44.         ListOfIdlers = new CSack;
  45.         ListOfIdlers->ISack(sizeof(CIdle*),128);
  46.         ListOfIdlerWannabees = new CSack;
  47.         ListOfIdlerWannabees->ISack(sizeof(CIdle*),4);
  48.         DeadIdlersList = new CSack;
  49.         DeadIdlersList->ISack(sizeof(CIdle*),4);
  50.         ActiveWindow = NIL;
  51.         KeyReceiverViewRect = NIL;
  52.         LastCursorTime = TickCount();
  53.     }
  54.  
  55.  
  56. /* dispose any variables */
  57. void        ShutDownMyEventLoop(void)
  58.     {
  59.         delete ListOfIdlers;
  60.         delete ListOfIdlerWannabees;
  61.         delete DeadIdlersList;
  62.     }
  63.  
  64.  
  65. void        TheEventLoop(CWindow* TheModalWindow)
  66.     {
  67.         EventRecord        MyEvent;
  68.         WindowPtr            WhichWindow;
  69.         MyEventRec        SpiffEvent;
  70.         short                    MenuCommand;
  71.         ulong                    MenuCommandStart;
  72.  
  73.      Loop:
  74.         if (QuitPending || ModalWindowTerminationFlag)
  75.             {
  76.                 ModalWindowTerminationFlag = False;
  77.                 return;
  78.             }
  79.         ERROR((ActiveWindow==NIL)&&(KeyReceiverViewRect!=NIL),PRERR(ForceAbort,
  80.             "There is no active window, yet there is a key receiver view rect."));
  81.         APRINT((""));
  82. //    if (((signed long)TickCount() - LastIdleTime > SleepTime)
  83. //        && ((signed long)TickCount() - LastIdleTime > (3*DefaultSleepTime/2)))
  84. //        {
  85. //            SendIdleToAll();
  86. //            APRINT((""));
  87. //        }
  88.         WaitNextEvent(everyEvent,&MyEvent,SleepTime,NIL);
  89.         if (MyEvent.what != nullEvent)
  90.             {
  91.                 LastEventTime = MyEvent.when;
  92.             }
  93.         /* "Stress-testing" idea taken from ResEdit. */
  94.         EXECUTE(PurgeMem(0x007fffff);) /* purge all blocks from zone */
  95.         EXECUTE(CompactMem(0x007fffff);) /* compact whole zone */
  96.         CheckHeap();
  97.         SpiffEvent.Where.x = MyEvent.where.h;
  98.         SpiffEvent.Where.y = MyEvent.where.v;
  99.         SpiffEvent.When = MyEvent.when;
  100.         SpiffEvent.Modifiers = MyEvent.modifiers;
  101.         SpiffEvent.Message = MyEvent.message;
  102.         LastModifiers = MyEvent.modifiers;
  103.         LastModifiersTime = MyEvent.when;
  104.         switch (MyEvent.what)
  105.             {
  106.                 case nullEvent:
  107.                     SendIdleToAll();
  108.                     if (((signed long)TickCount() - LastCursorTime > DefaultSleepTime)
  109.                         && WeAreActiveApplication)
  110.                         {
  111.                             LastCursorTime = TickCount();
  112.                             if ((FindWindow(MyEvent.where,&WhichWindow) != inContent)
  113.                                 || ((CWindow*)GetWRefCon(WhichWindow) != ActiveWindow)
  114.                                 || (!((CWindow*)GetWRefCon(WhichWindow))
  115.                                 ->DoMouseMoved(SpiffEvent)))
  116.                                 {
  117.                                     SetCursor(&arrow);
  118.                                 }
  119.                         }
  120.                     break;
  121.                 case mouseDown:
  122.                     APRINT(("Mousedown"));
  123.                     switch (FindWindow(MyEvent.where,&WhichWindow))
  124.                         {
  125.                             case inSysWindow:
  126.                                 SystemClick(&MyEvent,WhichWindow);
  127.                                 break;
  128.                             case inMenuBar:
  129.                                 MenuCommand = MenuMouseDown(&MyEvent);
  130.                                 if (  (KeyReceiverViewRect == NIL) || ( (KeyReceiverViewRect != NIL)
  131.                                     && (!KeyReceiverViewRect->DoMenuCommand(MenuCommand)) )  )
  132.                                     {
  133.                                         if (ActiveWindow != NIL)
  134.                                             {
  135.                                                 ActiveWindow->DoMenuCommand(MenuCommand);
  136.                                             }
  137.                                     }
  138.                                 HiliteMenu(0);
  139.                                 break;
  140.                             case inDrag:
  141.                                 if ((TheModalWindow == NIL) || (TheModalWindow
  142.                                     == (CWindow*)GetWRefCon(WhichWindow)))
  143.                                     {
  144.                                         ((CWindow*)GetWRefCon(WhichWindow))->DoDrag(MyEvent.where);
  145.                                     }
  146.                                  else
  147.                                     {
  148.                                         SysBeep(20);
  149.                                     }
  150.                                 break;
  151.                             case inContent:
  152.                              InContentPoint:
  153.                                 if ((TheModalWindow == NIL) || (TheModalWindow
  154.                                     == (CWindow*)GetWRefCon(WhichWindow)))
  155.                                     {
  156.                                         ((CWindow*)GetWRefCon(WhichWindow))->DoMouseDown(SpiffEvent);
  157.                                     }
  158.                                  else
  159.                                     {
  160.                                         SysBeep(20);
  161.                                     }
  162.                                 break;
  163.                             case inGrow:
  164.                                 if (((CWindow*)GetWRefCon(WhichWindow))->Growable)
  165.                                     {
  166.                                         ((CWindow*)GetWRefCon(WhichWindow))->DoGrow(MyEvent.where);
  167.                                     }
  168.                                  else
  169.                                     {
  170.                                         goto InContentPoint;
  171.                                     }
  172.                                 break;
  173.                             case inGoAway:
  174.                                 ((CWindow*)GetWRefCon(WhichWindow))->DoGoAway(MyEvent.where);
  175.                                 break;
  176.                             case inZoomIn:
  177.                                 ((CWindow*)GetWRefCon(WhichWindow))->DoZoomIn(MyEvent.where);
  178.                                 break;
  179.                             case inZoomOut:
  180.                                 ((CWindow*)GetWRefCon(WhichWindow))->DoZoomOut(MyEvent.where);
  181.                                 break;
  182.                             default:
  183.                                 break;
  184.                         }
  185.                     break;
  186.                 case mouseUp:
  187.                     APRINT(("MouseUp"));
  188.                     if (LastMouseDownViewRect != NIL)
  189.                         {
  190.                             LastMouseDownViewRect->DoMouseUp(SpiffEvent);
  191.                         }
  192.                     break;
  193.                 case keyDown:
  194.                     APRINT(("KeyDown"));
  195.                     if ((MyEvent.modifiers & cmdKey) != 0)
  196.                         {
  197.                             MenuCommand = MenuKeyDown(&MyEvent);
  198.                             if (MenuCommand == 0)
  199.                                 {
  200.                                     goto OtherKeyDown; /* if there is no menu */
  201.                                 }
  202.                             MenuCommandStart = TickCount();
  203.                             if (  (KeyReceiverViewRect == NIL) || ( (KeyReceiverViewRect != NIL)
  204.                                 && (!KeyReceiverViewRect->DoMenuCommand(MenuCommand)) )  )
  205.                                 {
  206.                                     if (ActiveWindow != NIL)
  207.                                         {
  208.                                             ActiveWindow->DoMenuCommand(MenuCommand);
  209.                                         }
  210.                                 }
  211.                             while (TickCount() - MenuCommandStart < MENUMINFLASH)
  212.                                 {
  213.                                 }
  214.                             HiliteMenu(0);
  215.                         }
  216.                      else
  217.                         {
  218.                             if (KeyReceiverViewRect != NIL)
  219.                                 {
  220.                                     LastKeyDownViewRect = KeyReceiverViewRect;
  221.                                     if (!KeyReceiverViewRect->DoKeyDown(SpiffEvent))
  222.                                         {
  223.                                             goto OtherKeyDown;
  224.                                         }
  225.                                 }
  226.                              else
  227.                                 {
  228.                                  OtherKeyDown:
  229.                                     if (ActiveWindow != NIL)
  230.                                         {
  231.                                             ActiveWindow->DoKeyDown(SpiffEvent);
  232.                                         }
  233.                                 }
  234.                         }
  235.                     break;
  236.                 case keyUp:
  237.                     APRINT(("KeyUp"));
  238.                     if (LastKeyDownViewRect != NIL)
  239.                         {
  240.                             LastKeyDownViewRect->DoKeyUp(SpiffEvent);
  241.                         }
  242.                     break;
  243.                 case autoKey:
  244.                     APRINT(("AutoKey"));
  245.                     if (LastKeyDownViewRect != NIL)
  246.                         {
  247.                             LastKeyDownViewRect->DoKeyDown(SpiffEvent);
  248.                         }
  249.                     break;
  250.                 case updateEvt:
  251.                     APRINT(("UpdateEvent"));
  252.                     ((CWindow*)GetWRefCon((WindowPtr)MyEvent.message))->DoUpdate();
  253.                     break;
  254.                 case activateEvt:
  255.                     APRINT(("ActivateEvent"));
  256.                     if ((MyEvent.modifiers & activeFlag) != 0)
  257.                         {
  258.                             /* activate */
  259.                             /* ERROR(ActiveWindow!=NIL,PRERR(ForceAbort,
  260.                                 "Activate event Received while a window was active.")); */
  261.                             if (ActiveWindow != NIL)
  262.                                 {
  263.                                     ActiveWindow->DoSuspend();
  264.                                 }
  265.                             ActiveWindow = ((CWindow*)GetWRefCon((WindowPtr)MyEvent.message));
  266.                             ActiveWindow->DoResume();
  267.                         }
  268.                      else
  269.                         {
  270.                             /* deactivate */
  271.                             /* ERROR(ActiveWindow==NIL,PRERR(ForceAbort,
  272.                                 "Deactivate event Received while no window was active.")); */
  273.                             if (ActiveWindow != NIL)
  274.                                 {
  275.                                     ActiveWindow->DoSuspend();
  276.                                     ActiveWindow = NIL;
  277.                                 }
  278.                         }
  279.                     break;
  280.                 case osEvt:
  281.                     APRINT(("OSEvent"));
  282.                     switch ((MyEvent.message >> 24) & 0x000000ff)
  283.                         {
  284.                             case suspendResumeMessage:
  285.                                 if (!(MyEvent.message & resumeFlag))
  286.                                     {
  287.                                         /* suspend */
  288.                                         WeAreActiveApplication = False;
  289.                                         if (ActiveWindow != NIL)
  290.                                             {
  291.                                                 ActiveWindow->DoSuspend();
  292.                                             }
  293.                                         /* ActiveWindow remains valid, so that it can be reactivated later */
  294.                                         if (MyEvent.message & convertClipboardFlag)
  295.                                             {
  296.                                                 Scrap->ExportScrap();
  297.                                             }
  298.                                     }
  299.                                  else
  300.                                     {
  301.                                         /* resume */
  302.                                         WeAreActiveApplication = True;
  303.                                         ActiveWindow = (CWindow*)GetWRefCon(FrontWindow());
  304.                                         if (ActiveWindow != NIL)
  305.                                             {
  306.                                                 ActiveWindow->DoResume();
  307.                                             }
  308.                                          else
  309.                                             {
  310.                                                 ActiveWindow = Application;
  311.                                                 Application->DoResume();
  312.                                             }
  313.                                         if (MyEvent.message & convertClipboardFlag)
  314.                                             {
  315.                                                 Scrap->ImportScrap();
  316.                                             }
  317.                                     }
  318.                                 break;
  319.                             case mouseMovedMessage:
  320.                                 break;
  321.                         }
  322.                     break;
  323.                 case kHighLevelEvent:
  324.                     if (TheModalWindow == NIL)
  325.                         {
  326.                             /* don't accept high level events when there's a modal window up */
  327.                             APRINT(("HighLevelEvent"));
  328.                             Application->ReceiveHighLevelEvent(&MyEvent);
  329.                         }
  330.                     break;
  331.                 default:
  332.                     APRINT(("UnknownEvent"));
  333.                     break;
  334.             }
  335.         goto Loop;
  336.     }
  337.  
  338.  
  339. /********************************************************************************/
  340. /* Idle Tracking Stuff */
  341.  
  342.  
  343. /* send an idle event to all idlers */
  344. /* be very careful with this function since it can cause big time recursion */
  345. /* if you call it from something that can be reached by the idle handler */
  346. void        SendIdleToAll(void)
  347.     {
  348.         CIdle*        Item;
  349.         long            TimeSinceLastEvent;
  350.         CIdle*        DeadOne;
  351.         EXECUTE(long                    Sizer;)
  352.         EXECUTE(static long        AuditLastIdleTime;)
  353.         EXECUTE(long                    TickTemp;)
  354.  
  355.         StackSizeTest();
  356.  
  357.         EXECUTE(TickTemp = TickCount();)
  358.         APRINT(("%l between idles",TickTemp - AuditLastIdleTime));
  359.         EXECUTE(AuditLastIdleTime = TickTemp;)
  360.  
  361.         TimeSinceLastEvent = TickCount() - LastEventTime;
  362.  
  363.         /* traversing list of idlers and calling their idle handlers */
  364.         ListOfIdlers->ResetScan();
  365.         while (ListOfIdlers->GetNext(&Item))
  366.             {
  367.                 if (DeadIdlersList->NumElements() != 0)
  368.                     {
  369.                         DeadIdlersList->ResetScan();
  370.                         while (DeadIdlersList->GetNext(&DeadOne))
  371.                             {
  372.                                 if (DeadOne == Item)
  373.                                     {
  374.                                         goto Escape; /* if idler died while in outer loop, can't call it */
  375.                                     }
  376.                             }
  377.                     }
  378.                 CheckHandleExistence((Handle)Item);
  379.                 EXECUTE(Sizer = HandleSize((Handle)Item));
  380.                 ERROR(Sizer < 0,PRERR(ForceAbort,"CIdle object found to have negative size."));
  381.                 Item->DoIdle(TimeSinceLastEvent);
  382.              Escape:
  383.                 ;
  384.             }
  385.  
  386.         /* removing idlers from list.  Must be done first in case a new idler picked */
  387.         /* up the same handle as a dead one. */
  388.         while (DeadIdlersList->NumElements() != 0)
  389.             {
  390.                 DeadIdlersList->ResetScan();
  391.                 DeadIdlersList->GetNext(&DeadOne);
  392.                 ListOfIdlers->KillElement(&DeadOne);
  393.                 DeadIdlersList->KillElement(&DeadOne);
  394.  
  395.                 /* finding new lowest sleep time. */
  396.                 SleepTime = DefaultSleepTime;
  397.                 ListOfIdlers->ResetScan();
  398.                 while (ListOfIdlers->GetNext(&Item))
  399.                     {
  400.                         if (SleepTime > Item->MinSleepTime)
  401.                             {
  402.                                 SleepTime = Item->MinSleepTime;
  403.                             }
  404.                     }
  405.             }
  406.  
  407.         /* adding idlers to the list.  We have to shadow adds to the list in case */
  408.         /* some things decide to add themselves as idlers as the previous loop */
  409.         /* is in progress */
  410.         while (ListOfIdlerWannabees->NumElements() != 0)
  411.             {
  412.                 ListOfIdlerWannabees->ResetScan();
  413.                 ListOfIdlerWannabees->GetNext(&Item);
  414.                 ListOfIdlerWannabees->KillElement(&Item);
  415.                 ListOfIdlers->KillElement(&Item);
  416.                 if (SleepTime > Item->MinSleepTime)
  417.                     {
  418.                         SleepTime = Item->MinSleepTime;
  419.                     }
  420.                 ListOfIdlers->PushElement(&Item);
  421.             }
  422.  
  423.         LastIdleTime = TickCount();
  424.  
  425.         /* at this point we have a problem:  say the idle loop was invoked and */
  426.         /* one of the idle routines created a dialog box, so the idle loop gets */
  427.         /* invoked again.  This means the internal pointer for ListOfIdlers */
  428.         /* gets messed up, and may even be invalid when the routine returns to */
  429.         /* the first idle loop.  To prevent that, we just resent the internal */
  430.         /* pointer to the beginning of the list, making this routine reentrant. */
  431.         ListOfIdlers->ResetScan();
  432.  
  433.         EXECUTE(TickTemp = TickCount();)
  434.         APRINT(("%l in idle",TickTemp-AuditLastIdleTime));
  435.         EXECUTE(AuditLastIdleTime = TickTemp;)
  436.     }
  437.  
  438.  
  439. /* add an object to the idle-time task list */
  440. void        RegisterIdler(CIdle* TheIdler, long MinSleepTime)
  441.     {
  442.         TheIdler->MinSleepTime = MinSleepTime;
  443.         ListOfIdlerWannabees->PushElement(&TheIdler);
  444.         EXECUTE(TheIdler->Installed = True;)
  445.     }
  446.  
  447.  
  448. /* remove an object from the idle-time task list */
  449. void        DeregisterIdler(CIdle* TheIdler)
  450.     {
  451.         DeadIdlersList->PushElement(&TheIdler);
  452.         ListOfIdlerWannabees->KillElement(&TheIdler);
  453.         EXECUTE(TheIdler->Installed = False;)
  454.     }
  455.  
  456.  
  457. /* the idle's function */
  458. void        CIdle::DoIdle(long TimeSinceLastEvent)
  459.     {
  460.     }
  461.  
  462. #ifdef DEBUG
  463.     
  464. /* */        CIdle::CIdle()
  465.     {
  466.         Installed = False;
  467.     }
  468.  
  469. /* */     CIdle::~CIdle()
  470.     {
  471.         ERROR(Installed,PRERR(ForceAbort,"Deleting an installed idler"));
  472.     }
  473.  
  474. #endif
  475.  
  476.  
  477. /********************************************************************************/
  478.  
  479.  
  480. /* certain race conditions or crashes can occur when using this function. */
  481. /* - do not call this from the Scrap object since it may cause the scrap */
  482. /*   to be imported or exported */
  483. /* - this calls update, suspend, and resume, so any window structures must */
  484. /*   be completely initialized if you want to call this */
  485. /* Finally, it returns True if the user cancelled and False if not. */
  486. MyBoolean            RelinquishCPU(void)
  487.     {
  488.         EventRecord            StupidEvent;
  489.         MyBoolean                CancelFlag;
  490.  
  491.         CancelFlag = False;
  492.      TryAgainPoint:
  493.         WaitNextEvent(updateMask | keyDownMask | keyUpMask | mDownMask | mUpMask
  494.             | osMask | autoKeyMask | diskMask,&StupidEvent,RELINQUISHSLEEPTIME,NIL);
  495.         LastModifiers = StupidEvent.modifiers;
  496.         LastModifiersTime = StupidEvent.when;
  497.         switch (StupidEvent.what)
  498.             {
  499.                 case keyDown:
  500.                     if ((((StupidEvent.message & charCodeMask) == '.')
  501.                         && ((StupidEvent.modifiers & cmdKey) != 0)) ||
  502.                         (((StupidEvent.message & charCodeMask) == 3)
  503.                         && ((StupidEvent.modifiers & controlKey) != 0)))
  504.                         {
  505.                             CancelFlag = True;
  506.                         }
  507.                     break;
  508.                 case updateEvt:
  509.                     APRINT(("UpdateEvent"));
  510.                     /* this helps "live" scrolling when part of the region is not */
  511.                     /* on the screen.  Since the scrollbars always call RelinquishCPU */
  512.                     /* frequently, this works well here. */
  513.                     ((CWindow*)GetWRefCon((WindowPtr)StupidEvent.message))->DoUpdate();
  514.                     /* since the purpose of this routine is to give other processes */
  515.                     /* a chance to run, if we update, we don't do that so we go and */
  516.                     /* try another event. */
  517.                     goto TryAgainPoint;
  518.                 case osEvt:
  519.                     APRINT(("OSEvent"));
  520.                     switch ((StupidEvent.message >> 24) & 0x000000ff)
  521.                         {
  522.                             case suspendResumeMessage:
  523.                                 if (!(StupidEvent.message & resumeFlag))
  524.                                     {
  525.                                         /* suspend */
  526.                                         WeAreActiveApplication = False;
  527.                                         if (ActiveWindow != NIL)
  528.                                             {
  529.                                                 ActiveWindow->DoSuspend();
  530.                                             }
  531.                                         /* ActiveWindow remains valid, so that it can be reactivated later */
  532.                                         if (StupidEvent.message & convertClipboardFlag)
  533.                                             {
  534.                                                 Scrap->ExportScrap();
  535.                                             }
  536.                                     }
  537.                                  else
  538.                                     {
  539.                                         /* resume */
  540.                                         WeAreActiveApplication = True;
  541.                                         ActiveWindow = (CWindow*)GetWRefCon(FrontWindow());
  542.                                         if (ActiveWindow != NIL)
  543.                                             {
  544.                                                 ActiveWindow->DoResume();
  545.                                             }
  546.                                          else
  547.                                             {
  548.                                                 ActiveWindow = Application;
  549.                                                 Application->DoResume();
  550.                                             }
  551.                                         if (StupidEvent.message & convertClipboardFlag)
  552.                                             {
  553.                                                 Scrap->ImportScrap();
  554.                                             }
  555.                                     }
  556.                                 break;
  557.                             case mouseMovedMessage:
  558.                                 break;
  559.                         }
  560.                     break;
  561.                 default:
  562.                     break;
  563.             }
  564.         LastJudiciousRelease = TickCount();
  565.         return CancelFlag;
  566.     }
  567.  
  568.  
  569. /* see notes on RelinquishCPU about possible problems */
  570. /* returns True if the user cancelled, and False if not */
  571. MyBoolean         RelinquishCPUJudiciously(void)
  572.     {
  573.         if (TickCount() - LastJudiciousRelease > JudiciousDelay)
  574.             {
  575.                 return RelinquishCPU();
  576.             }
  577.          else
  578.             {
  579.                 return False;
  580.             }
  581.     }
  582.  
  583.  
  584. /* be very careful with this function since it can cause big time recursion */
  585. /* if you call it from something that can be reached by the idle handler */
  586. void                    SendIdleToAllJudiciously(void)
  587.     {
  588.         if (TickCount() - LastIdleTime > ((SleepTime > 2) ? SleepTime : 2))
  589.             {
  590.                 SendIdleToAll();
  591.             }
  592.     }
  593.